2018-01-22 22:38:48 +08:00
|
|
|
// Copyright (c) 2014-2018 Thomas Fussell
|
2015-12-25 04:51:11 +08:00
|
|
|
// Copyright (c) 2010-2015 openpyxl
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
// THE SOFTWARE
|
|
|
|
//
|
|
|
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
|
|
// @author: see AUTHORS file
|
2016-11-20 05:50:35 +08:00
|
|
|
|
2014-05-22 05:48:51 +08:00
|
|
|
#include <algorithm>
|
2016-06-11 22:09:29 +08:00
|
|
|
#include <cmath>
|
2014-05-21 22:20:30 +08:00
|
|
|
#include <sstream>
|
|
|
|
|
2017-04-21 02:03:03 +08:00
|
|
|
#include <detail/implementations/cell_impl.hpp>
|
|
|
|
#include <detail/implementations/format_impl.hpp>
|
2018-03-17 09:21:16 +08:00
|
|
|
#include <detail/implementations/hyperlink_impl.hpp>
|
2017-04-21 02:03:03 +08:00
|
|
|
#include <detail/implementations/stylesheet.hpp>
|
2017-09-09 07:41:34 +08:00
|
|
|
#include <detail/implementations/worksheet_impl.hpp>
|
2014-08-14 06:56:34 +08:00
|
|
|
#include <xlnt/cell/cell.hpp>
|
|
|
|
#include <xlnt/cell/cell_reference.hpp>
|
|
|
|
#include <xlnt/cell/comment.hpp>
|
2018-03-17 09:21:16 +08:00
|
|
|
#include <xlnt/cell/hyperlink.hpp>
|
2016-12-23 19:51:30 +08:00
|
|
|
#include <xlnt/cell/rich_text.hpp>
|
2018-01-27 03:32:00 +08:00
|
|
|
#include <xlnt/packaging/manifest.hpp>
|
2015-11-03 21:38:09 +08:00
|
|
|
#include <xlnt/packaging/relationship.hpp>
|
2016-11-08 10:11:30 +08:00
|
|
|
#include <xlnt/styles/alignment.hpp>
|
|
|
|
#include <xlnt/styles/border.hpp>
|
2015-11-03 21:38:09 +08:00
|
|
|
#include <xlnt/styles/color.hpp>
|
2016-11-08 10:11:30 +08:00
|
|
|
#include <xlnt/styles/fill.hpp>
|
|
|
|
#include <xlnt/styles/font.hpp>
|
2016-06-11 01:40:50 +08:00
|
|
|
#include <xlnt/styles/format.hpp>
|
2016-11-08 10:11:30 +08:00
|
|
|
#include <xlnt/styles/number_format.hpp>
|
|
|
|
#include <xlnt/styles/protection.hpp>
|
2016-06-11 01:40:50 +08:00
|
|
|
#include <xlnt/styles/style.hpp>
|
2015-11-20 11:54:54 +08:00
|
|
|
#include <xlnt/utils/date.hpp>
|
2015-11-03 21:38:09 +08:00
|
|
|
#include <xlnt/utils/datetime.hpp>
|
2016-11-20 05:50:35 +08:00
|
|
|
#include <xlnt/utils/exceptions.hpp>
|
2015-11-20 11:54:54 +08:00
|
|
|
#include <xlnt/utils/time.hpp>
|
|
|
|
#include <xlnt/utils/timedelta.hpp>
|
2014-08-14 06:56:34 +08:00
|
|
|
#include <xlnt/workbook/workbook.hpp>
|
2015-11-01 22:43:01 +08:00
|
|
|
#include <xlnt/worksheet/column_properties.hpp>
|
|
|
|
#include <xlnt/worksheet/row_properties.hpp>
|
2015-10-19 03:30:46 +08:00
|
|
|
#include <xlnt/worksheet/worksheet.hpp>
|
2018-11-21 20:52:07 +08:00
|
|
|
#include <xlnt/worksheet/phonetic_pr.hpp>
|
2014-08-14 06:56:34 +08:00
|
|
|
|
2016-05-12 07:24:53 +08:00
|
|
|
namespace {
|
|
|
|
|
2017-09-09 09:05:34 +08:00
|
|
|
std::pair<bool, double> cast_numeric(const std::string &s)
|
2016-05-12 07:24:53 +08:00
|
|
|
{
|
2016-12-24 23:04:57 +08:00
|
|
|
auto str_end = static_cast<char *>(nullptr);
|
2017-09-09 10:59:19 +08:00
|
|
|
auto result = std::strtod(s.c_str(), &str_end);
|
2016-12-24 23:04:57 +08:00
|
|
|
|
|
|
|
return (str_end != s.c_str() + s.size())
|
2017-09-09 09:05:34 +08:00
|
|
|
? std::make_pair(false, 0.0)
|
2016-12-24 23:04:57 +08:00
|
|
|
: std::make_pair(true, result);
|
2016-05-12 07:24:53 +08:00
|
|
|
}
|
|
|
|
|
2017-09-09 09:05:34 +08:00
|
|
|
std::pair<bool, double> cast_percentage(const std::string &s)
|
2016-05-12 07:24:53 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
if (s.back() == '%')
|
|
|
|
{
|
|
|
|
auto number = cast_numeric(s.substr(0, s.size() - 1));
|
2016-05-12 07:24:53 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
if (number.first)
|
|
|
|
{
|
|
|
|
return {true, number.second / 100};
|
|
|
|
}
|
|
|
|
}
|
2016-05-12 07:24:53 +08:00
|
|
|
|
2017-09-09 09:05:34 +08:00
|
|
|
return {false, 0.0};
|
2016-05-12 07:24:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<bool, xlnt::time> cast_time(const std::string &s)
|
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
xlnt::time result;
|
2016-05-12 07:24:53 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
std::vector<std::string> time_components;
|
|
|
|
std::size_t prev = 0;
|
|
|
|
auto colon_index = s.find(':');
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
while (colon_index != std::string::npos)
|
|
|
|
{
|
|
|
|
time_components.push_back(s.substr(prev, colon_index - prev));
|
|
|
|
prev = colon_index + 1;
|
|
|
|
colon_index = s.find(':', colon_index + 1);
|
|
|
|
}
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
time_components.push_back(s.substr(prev, colon_index - prev));
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
if (time_components.size() < 2 || time_components.size() > 3)
|
|
|
|
{
|
|
|
|
return {false, result};
|
|
|
|
}
|
2016-05-12 07:24:53 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
std::vector<double> numeric_components;
|
2016-05-12 07:24:53 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
for (auto component : time_components)
|
|
|
|
{
|
|
|
|
if (component.empty() || (component.substr(0, component.find('.')).size() > 2))
|
|
|
|
{
|
|
|
|
return {false, result};
|
|
|
|
}
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
for (auto d : component)
|
|
|
|
{
|
|
|
|
if (!(d >= '0' && d <= '9') && d != '.')
|
|
|
|
{
|
|
|
|
return {false, result};
|
|
|
|
}
|
|
|
|
}
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
auto without_leading_zero = component.front() == '0' ? component.substr(1) : component;
|
|
|
|
auto numeric = std::stod(without_leading_zero);
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
numeric_components.push_back(numeric);
|
|
|
|
}
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
result.hour = static_cast<int>(numeric_components[0]);
|
|
|
|
result.minute = static_cast<int>(numeric_components[1]);
|
2016-08-06 22:40:17 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
if (std::fabs(static_cast<double>(result.minute) - numeric_components[1]) > std::numeric_limits<double>::epsilon())
|
|
|
|
{
|
|
|
|
result.minute = result.hour;
|
|
|
|
result.hour = 0;
|
|
|
|
result.second = static_cast<int>(numeric_components[1]);
|
|
|
|
result.microsecond = static_cast<int>((numeric_components[1] - result.second) * 1E6);
|
|
|
|
}
|
|
|
|
else if (numeric_components.size() > 2)
|
|
|
|
{
|
|
|
|
result.second = static_cast<int>(numeric_components[2]);
|
|
|
|
result.microsecond = static_cast<int>((numeric_components[2] - result.second) * 1E6);
|
|
|
|
}
|
2016-05-12 07:24:53 +08:00
|
|
|
|
2016-11-20 05:50:35 +08:00
|
|
|
return {true, result};
|
2016-05-12 07:24:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2014-07-26 04:39:25 +08:00
|
|
|
namespace xlnt {
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2015-11-11 07:58:54 +08:00
|
|
|
const std::unordered_map<std::string, int> &cell::error_codes()
|
2015-10-30 01:46:56 +08:00
|
|
|
{
|
2016-12-24 23:04:57 +08:00
|
|
|
static const auto *codes = new std::unordered_map<std::string, int>{
|
2016-11-20 05:50:35 +08:00
|
|
|
{"#NULL!", 0},
|
|
|
|
{"#DIV/0!", 1},
|
|
|
|
{"#VALUE!", 2},
|
|
|
|
{"#REF!", 3},
|
|
|
|
{"#NAME?", 4},
|
|
|
|
{"#NUM!", 5},
|
2016-12-24 23:04:57 +08:00
|
|
|
{"#N/A!", 6}};
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2015-11-03 05:45:05 +08:00
|
|
|
return *codes;
|
2016-11-08 10:11:30 +08:00
|
|
|
}
|
2014-05-21 22:20:30 +08:00
|
|
|
|
2015-11-23 01:41:27 +08:00
|
|
|
std::string cell::check_string(const std::string &to_check)
|
|
|
|
{
|
|
|
|
// so we can modify it
|
|
|
|
std::string s = to_check;
|
|
|
|
|
|
|
|
if (s.size() == 0)
|
|
|
|
{
|
|
|
|
return s;
|
|
|
|
}
|
2016-07-18 01:49:59 +08:00
|
|
|
else if (s.size() > 32767)
|
2015-11-23 01:41:27 +08:00
|
|
|
{
|
|
|
|
s = s.substr(0, 32767); // max string length in Excel
|
|
|
|
}
|
|
|
|
|
|
|
|
for (char c : s)
|
|
|
|
{
|
|
|
|
if (c >= 0 && (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31)))
|
|
|
|
{
|
2016-08-16 12:23:49 +08:00
|
|
|
throw illegal_character(c);
|
2015-11-23 01:41:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2016-12-24 23:04:57 +08:00
|
|
|
cell::cell(detail::cell_impl *d)
|
|
|
|
: d_(d)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-07-26 04:39:25 +08:00
|
|
|
bool cell::garbage_collectible() const
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2018-11-21 20:52:07 +08:00
|
|
|
return !(has_value() || is_merged() || phonetics_visible() || has_formula() || has_format() || has_hyperlink());
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(std::nullptr_t)
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
clear_value();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(bool boolean_value)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2015-10-14 01:56:07 +08:00
|
|
|
d_->type_ = type::boolean;
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = boolean_value ? 1.0 : 0.0;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(int int_value)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = static_cast<double>(int_value);
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(unsigned int int_value)
|
2014-05-31 06:42:25 +08:00
|
|
|
{
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = static_cast<double>(int_value);
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2014-05-31 06:42:25 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(long long int int_value)
|
2015-10-02 06:14:42 +08:00
|
|
|
{
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = static_cast<double>(int_value);
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2015-10-02 06:14:42 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(unsigned long long int int_value)
|
2015-10-02 06:14:42 +08:00
|
|
|
{
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = static_cast<double>(int_value);
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2015-10-02 06:14:42 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(float float_value)
|
2015-10-02 06:14:42 +08:00
|
|
|
{
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = static_cast<double>(float_value);
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2015-10-02 06:14:42 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(double float_value)
|
2015-10-02 06:14:42 +08:00
|
|
|
{
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = static_cast<double>(float_value);
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2015-10-02 06:14:42 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const std::string &s)
|
2015-10-02 06:14:42 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
value(rich_text(check_string(s)));
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const rich_text &text)
|
2016-05-15 03:19:08 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
check_string(text.plain_text());
|
|
|
|
|
|
|
|
d_->type_ = type::shared_string;
|
2017-09-09 09:05:34 +08:00
|
|
|
d_->value_numeric_ = static_cast<double>(workbook().add_shared_string(text));
|
2016-05-15 03:19:08 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const char *c)
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
value(std::string(c));
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
2015-10-14 04:35:22 +08:00
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const cell c)
|
2015-10-14 04:35:22 +08:00
|
|
|
{
|
2015-10-15 06:05:13 +08:00
|
|
|
d_->type_ = c.d_->type_;
|
|
|
|
d_->value_numeric_ = c.d_->value_numeric_;
|
2016-05-12 07:24:53 +08:00
|
|
|
d_->value_text_ = c.d_->value_text_;
|
2015-10-15 06:05:13 +08:00
|
|
|
d_->hyperlink_ = c.d_->hyperlink_;
|
|
|
|
d_->formula_ = c.d_->formula_;
|
2016-11-08 10:11:30 +08:00
|
|
|
d_->format_ = c.d_->format_;
|
2015-10-14 04:35:22 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const date &d)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2016-12-02 21:37:50 +08:00
|
|
|
d_->value_numeric_ = d.to_number(base_date());
|
|
|
|
number_format(number_format::date_yyyymmdd2());
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const datetime &d)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2016-12-02 21:37:50 +08:00
|
|
|
d_->value_numeric_ = d.to_number(base_date());
|
|
|
|
number_format(number_format::date_datetime());
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const time &t)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2015-10-19 03:30:46 +08:00
|
|
|
d_->value_numeric_ = t.to_number();
|
2016-12-02 21:37:50 +08:00
|
|
|
number_format(number_format::date_time6());
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-21 07:20:12 +08:00
|
|
|
void cell::value(const timedelta &t)
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = type::number;
|
2015-10-19 03:30:46 +08:00
|
|
|
d_->value_numeric_ = t.to_number();
|
2016-12-02 21:37:50 +08:00
|
|
|
number_format(xlnt::number_format("[hh]:mm:ss"));
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
row_t cell::row() const
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2015-10-14 01:56:07 +08:00
|
|
|
return d_->row_;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
column_t cell::column() const
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2015-11-04 03:53:48 +08:00
|
|
|
return d_->column_;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2018-07-03 07:10:47 +08:00
|
|
|
column_t::index_t cell::column_index() const
|
|
|
|
{
|
|
|
|
return d_->column_.index;
|
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::merged(bool merged)
|
2014-06-05 06:42:17 +08:00
|
|
|
{
|
2015-10-14 01:56:07 +08:00
|
|
|
d_->is_merged_ = merged;
|
2014-06-05 06:42:17 +08:00
|
|
|
}
|
|
|
|
|
2014-07-26 04:39:25 +08:00
|
|
|
bool cell::is_merged() const
|
2014-06-11 05:12:15 +08:00
|
|
|
{
|
2015-10-14 01:56:07 +08:00
|
|
|
return d_->is_merged_;
|
2014-06-11 05:12:15 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 20:52:07 +08:00
|
|
|
bool cell::phonetics_visible() const
|
|
|
|
{
|
|
|
|
return d_->phonetics_visible_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cell::show_phonetics(bool phonetics)
|
|
|
|
{
|
|
|
|
d_->phonetics_visible_ = phonetics;
|
|
|
|
}
|
|
|
|
|
2014-07-26 04:39:25 +08:00
|
|
|
bool cell::is_date() const
|
2014-06-05 06:42:17 +08:00
|
|
|
{
|
2017-09-13 20:48:22 +08:00
|
|
|
return data_type() == type::number
|
|
|
|
&& has_format()
|
|
|
|
&& number_format().is_date_format();
|
2014-06-05 06:42:17 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
cell_reference cell::reference() const
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return {d_->column_, d_->row_};
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2014-07-26 04:39:25 +08:00
|
|
|
bool cell::operator==(const cell &comparand) const
|
2014-05-21 22:20:30 +08:00
|
|
|
{
|
2015-10-14 01:56:07 +08:00
|
|
|
return d_ == comparand.d_;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2018-07-10 13:19:56 +08:00
|
|
|
bool cell::operator!=(const cell &comparand) const
|
2014-05-31 06:42:25 +08:00
|
|
|
{
|
2018-07-10 13:19:56 +08:00
|
|
|
return d_ != comparand.d_;
|
2014-05-21 22:20:30 +08:00
|
|
|
}
|
|
|
|
|
2018-07-10 13:19:56 +08:00
|
|
|
cell &cell::operator=(const cell &rhs) = default;
|
|
|
|
|
2018-03-17 09:21:16 +08:00
|
|
|
hyperlink cell::hyperlink() const
|
2014-06-11 05:12:15 +08:00
|
|
|
{
|
2018-03-17 09:21:16 +08:00
|
|
|
return xlnt::hyperlink(&d_->hyperlink_.get());
|
2014-06-11 05:12:15 +08:00
|
|
|
}
|
2014-05-21 22:20:30 +08:00
|
|
|
|
2018-07-02 17:06:12 +08:00
|
|
|
void cell::hyperlink(const std::string &url, const std::string &display)
|
2014-06-11 05:12:15 +08:00
|
|
|
{
|
2018-08-04 10:55:17 +08:00
|
|
|
if (url.empty())
|
2014-06-11 05:12:15 +08:00
|
|
|
{
|
2016-08-16 12:23:49 +08:00
|
|
|
throw invalid_parameter();
|
2014-06-11 05:12:15 +08:00
|
|
|
}
|
|
|
|
|
2018-01-27 03:32:00 +08:00
|
|
|
auto ws = worksheet();
|
|
|
|
auto &manifest = ws.workbook().manifest();
|
|
|
|
|
2018-03-17 09:21:16 +08:00
|
|
|
d_->hyperlink_ = detail::hyperlink_impl();
|
|
|
|
|
|
|
|
// check for existing relationships
|
2018-06-16 13:02:34 +08:00
|
|
|
auto relationships = manifest.relationships(ws.path(), relationship_type::hyperlink);
|
|
|
|
auto relation = std::find_if(relationships.cbegin(), relationships.cend(),
|
|
|
|
[&url](xlnt::relationship rel) { return rel.target().path().string() == url; });
|
2018-07-02 17:06:12 +08:00
|
|
|
if (relation != relationships.end())
|
|
|
|
{
|
2018-06-16 13:02:34 +08:00
|
|
|
d_->hyperlink_.get().relationship = *relation;
|
2018-01-27 03:32:00 +08:00
|
|
|
}
|
2018-06-16 13:02:34 +08:00
|
|
|
else
|
|
|
|
{ // register a new relationship
|
2018-03-17 09:21:16 +08:00
|
|
|
auto rel_id = manifest.register_relationship(
|
|
|
|
uri(ws.path().string()),
|
|
|
|
relationship_type::hyperlink,
|
2018-03-21 21:03:37 +08:00
|
|
|
uri(url),
|
2018-03-17 09:21:16 +08:00
|
|
|
target_mode::external);
|
|
|
|
// TODO: make manifest::register_relationship return the created relationship instead of rel id
|
|
|
|
d_->hyperlink_.get().relationship = manifest.relationship(ws.path(), rel_id);
|
2018-01-27 03:32:00 +08:00
|
|
|
}
|
2018-07-02 17:06:12 +08:00
|
|
|
// if a value is already present, the display string is ignored
|
|
|
|
if (has_value())
|
2018-06-16 13:02:34 +08:00
|
|
|
{
|
2018-07-02 17:06:12 +08:00
|
|
|
d_->hyperlink_.get().display.set(to_string());
|
2018-06-16 13:02:34 +08:00
|
|
|
}
|
2018-07-02 17:06:12 +08:00
|
|
|
else
|
2018-06-16 13:02:34 +08:00
|
|
|
{
|
2018-07-02 17:06:12 +08:00
|
|
|
d_->hyperlink_.get().display.set(display.empty() ? url : display);
|
|
|
|
value(hyperlink().display());
|
2018-06-16 13:02:34 +08:00
|
|
|
}
|
2017-02-18 13:11:06 +08:00
|
|
|
}
|
|
|
|
|
2018-07-02 17:06:12 +08:00
|
|
|
void cell::hyperlink(xlnt::cell target, const std::string& display)
|
2017-02-18 13:11:06 +08:00
|
|
|
{
|
2018-03-17 09:21:16 +08:00
|
|
|
// TODO: should this computed value be a method on a cell?
|
|
|
|
const auto cell_address = target.worksheet().title() + "!" + target.reference().to_string();
|
|
|
|
|
|
|
|
d_->hyperlink_ = detail::hyperlink_impl();
|
|
|
|
d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink,
|
|
|
|
uri(""), uri(cell_address), target_mode::internal);
|
2018-07-02 17:06:12 +08:00
|
|
|
// if a value is already present, the display string is ignored
|
|
|
|
if (has_value())
|
|
|
|
{
|
|
|
|
d_->hyperlink_.get().display.set(to_string());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d_->hyperlink_.get().display.set(display.empty() ? cell_address : display);
|
|
|
|
value(hyperlink().display());
|
|
|
|
}
|
2014-06-11 05:12:15 +08:00
|
|
|
}
|
|
|
|
|
2018-07-02 17:06:12 +08:00
|
|
|
void cell::hyperlink(xlnt::range target, const std::string &display)
|
2018-07-02 06:29:58 +08:00
|
|
|
{
|
|
|
|
// TODO: should this computed value be a method on a cell?
|
2018-07-10 13:19:56 +08:00
|
|
|
const auto range_address = target.target_worksheet().title() + "!" + target.reference().to_string();
|
2018-07-02 06:29:58 +08:00
|
|
|
|
|
|
|
d_->hyperlink_ = detail::hyperlink_impl();
|
|
|
|
d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink,
|
|
|
|
uri(""), uri(range_address), target_mode::internal);
|
2018-07-02 17:06:12 +08:00
|
|
|
|
|
|
|
// if a value is already present, the display string is ignored
|
|
|
|
if (has_value())
|
|
|
|
{
|
|
|
|
d_->hyperlink_.get().display.set(to_string());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d_->hyperlink_.get().display.set(display.empty() ? range_address : display);
|
|
|
|
value(hyperlink().display());
|
|
|
|
}
|
2018-07-02 06:29:58 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::formula(const std::string &formula)
|
2014-06-11 05:12:15 +08:00
|
|
|
{
|
2016-08-06 22:40:17 +08:00
|
|
|
if (formula.empty())
|
2014-07-25 05:31:46 +08:00
|
|
|
{
|
2017-02-18 13:11:06 +08:00
|
|
|
return clear_formula();
|
2014-07-25 05:31:46 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
|
|
|
if (formula[0] == '=')
|
2015-10-26 12:26:48 +08:00
|
|
|
{
|
|
|
|
d_->formula_ = formula.substr(1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d_->formula_ = formula;
|
|
|
|
}
|
2017-05-10 20:44:25 +08:00
|
|
|
|
2017-02-18 13:11:06 +08:00
|
|
|
worksheet().register_calc_chain_in_manifest();
|
2014-07-25 05:31:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::has_formula() const
|
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return d_->formula_.is_set();
|
2014-07-25 05:31:46 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
std::string cell::formula() const
|
2014-07-25 05:31:46 +08:00
|
|
|
{
|
2016-08-16 12:23:49 +08:00
|
|
|
return d_->formula_.get();
|
2014-07-25 05:31:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void cell::clear_formula()
|
|
|
|
{
|
2017-02-25 22:54:38 +08:00
|
|
|
if (has_formula())
|
|
|
|
{
|
|
|
|
d_->formula_.clear();
|
|
|
|
worksheet().garbage_collect_formulae();
|
|
|
|
}
|
2014-06-11 05:12:15 +08:00
|
|
|
}
|
2014-05-31 06:42:25 +08:00
|
|
|
|
2018-07-02 06:29:58 +08:00
|
|
|
std::string cell::error() const
|
|
|
|
{
|
|
|
|
if (d_->type_ != type::error)
|
|
|
|
{
|
|
|
|
throw xlnt::exception("called error() when cell type is not error");
|
|
|
|
}
|
|
|
|
return value<std::string>();
|
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::error(const std::string &error)
|
2014-06-11 05:12:15 +08:00
|
|
|
{
|
2015-11-01 22:43:01 +08:00
|
|
|
if (error.length() == 0 || error[0] != '#')
|
2014-06-11 05:12:15 +08:00
|
|
|
{
|
2016-07-30 06:55:49 +08:00
|
|
|
throw invalid_data_type();
|
2014-06-11 05:12:15 +08:00
|
|
|
}
|
|
|
|
|
2018-05-29 11:13:57 +08:00
|
|
|
d_->value_text_.plain_text(error, false);
|
2015-10-14 01:56:07 +08:00
|
|
|
d_->type_ = type::error;
|
2014-06-11 05:12:15 +08:00
|
|
|
}
|
2014-05-31 06:42:25 +08:00
|
|
|
|
2015-11-04 03:53:48 +08:00
|
|
|
cell cell::offset(int column, int row)
|
2014-07-20 02:43:48 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return worksheet().cell(reference().make_offset(column, row));
|
2014-07-20 02:43:48 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
worksheet cell::worksheet()
|
2014-07-20 02:43:48 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return xlnt::worksheet(d_->parent_);
|
2014-07-20 02:43:48 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
const worksheet cell::worksheet() const
|
2014-07-26 04:39:25 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return xlnt::worksheet(d_->parent_);
|
2014-07-26 04:39:25 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
workbook &cell::workbook()
|
2016-05-12 07:24:53 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return worksheet().workbook();
|
2016-05-12 07:24:53 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
const workbook &cell::workbook() const
|
2016-05-12 07:24:53 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return worksheet().workbook();
|
2016-05-12 07:24:53 +08:00
|
|
|
}
|
2014-07-20 02:43:48 +08:00
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
std::pair<int, int> cell::anchor() const
|
2014-07-26 04:39:25 +08:00
|
|
|
{
|
2016-12-26 22:38:26 +08:00
|
|
|
double left = 0;
|
2014-07-26 04:39:25 +08:00
|
|
|
|
2016-12-24 23:04:57 +08:00
|
|
|
for (column_t column_index = 1; column_index <= d_->column_ - 1; column_index++)
|
2014-07-26 04:39:25 +08:00
|
|
|
{
|
2017-02-07 06:00:45 +08:00
|
|
|
left += worksheet().column_width(column_index);
|
2014-07-26 04:39:25 +08:00
|
|
|
}
|
|
|
|
|
2016-12-26 22:38:26 +08:00
|
|
|
double top = 0;
|
2014-07-26 04:39:25 +08:00
|
|
|
|
2016-12-24 23:04:57 +08:00
|
|
|
for (row_t row_index = 1; row_index <= d_->row_ - 1; row_index++)
|
2014-07-26 04:39:25 +08:00
|
|
|
{
|
2017-02-11 12:22:38 +08:00
|
|
|
top += worksheet().row_height(row_index);
|
|
|
|
}
|
2014-07-26 04:39:25 +08:00
|
|
|
|
2016-12-26 22:38:26 +08:00
|
|
|
return {static_cast<int>(left), static_cast<int>(top)};
|
2014-07-26 04:39:25 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
cell::type cell::data_type() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
|
|
|
return d_->type_;
|
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::data_type(type t)
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
|
|
|
d_->type_ = t;
|
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
number_format cell::computed_number_format() const
|
2015-10-14 04:35:22 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return xlnt::number_format();
|
2015-10-14 04:35:22 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
font cell::computed_font() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return xlnt::font();
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
fill cell::computed_fill() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return xlnt::fill();
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
border cell::computed_border() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return xlnt::border();
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
alignment cell::computed_alignment() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return xlnt::alignment();
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
protection cell::computed_protection() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return xlnt::protection();
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2015-10-14 01:56:07 +08:00
|
|
|
void cell::clear_value()
|
|
|
|
{
|
|
|
|
d_->value_numeric_ = 0;
|
2016-05-12 07:24:53 +08:00
|
|
|
d_->value_text_.clear();
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = cell::type::empty;
|
2017-01-03 08:12:23 +08:00
|
|
|
clear_formula();
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API bool cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2017-09-09 10:59:19 +08:00
|
|
|
return d_->value_numeric_ != 0.0;
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2017-03-22 07:51:16 +08:00
|
|
|
XLNT_API int cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2017-03-22 07:51:16 +08:00
|
|
|
return static_cast<int>(d_->value_numeric_);
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2017-03-22 07:51:16 +08:00
|
|
|
XLNT_API long long int cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2017-03-22 07:51:16 +08:00
|
|
|
return static_cast<long long int>(d_->value_numeric_);
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2017-03-22 07:51:16 +08:00
|
|
|
XLNT_API unsigned int cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2017-03-22 07:51:16 +08:00
|
|
|
return static_cast<unsigned int>(d_->value_numeric_);
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2017-03-22 07:51:16 +08:00
|
|
|
XLNT_API unsigned long long cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2017-03-22 07:51:16 +08:00
|
|
|
return static_cast<unsigned long long>(d_->value_numeric_);
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
2015-10-17 07:46:21 +08:00
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API float cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
|
|
|
return static_cast<float>(d_->value_numeric_);
|
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API double cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
|
|
|
return static_cast<double>(d_->value_numeric_);
|
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API time cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
|
|
|
return time::from_number(d_->value_numeric_);
|
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API datetime cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return datetime::from_number(d_->value_numeric_, base_date());
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API date cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return date::from_number(static_cast<int>(d_->value_numeric_), base_date());
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API timedelta cell::value() const
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2015-10-19 03:30:46 +08:00
|
|
|
return timedelta::from_number(d_->value_numeric_);
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
2015-10-14 02:19:46 +08:00
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::alignment(const class alignment &alignment_)
|
2016-11-01 20:50:29 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto new_format = has_format() ? modifiable_format() : workbook().create_format();
|
2018-04-25 05:58:17 +08:00
|
|
|
format(new_format.alignment(alignment_, optional<bool>(true)));
|
2016-11-01 20:50:29 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::border(const class border &border_)
|
2016-03-14 11:46:01 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto new_format = has_format() ? modifiable_format() : workbook().create_format();
|
2018-04-25 05:58:17 +08:00
|
|
|
format(new_format.border(border_, optional<bool>(true)));
|
2016-03-14 11:46:01 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::fill(const class fill &fill_)
|
2016-03-14 11:46:01 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto new_format = has_format() ? modifiable_format() : workbook().create_format();
|
2018-04-25 05:58:17 +08:00
|
|
|
format(new_format.fill(fill_, optional<bool>(true)));
|
2016-03-14 11:46:01 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::font(const class font &font_)
|
2015-11-23 01:41:27 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto new_format = has_format() ? modifiable_format() : workbook().create_format();
|
2018-04-25 05:58:17 +08:00
|
|
|
format(new_format.font(font_, optional<bool>(true)));
|
2015-11-23 01:41:27 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::number_format(const class number_format &number_format_)
|
2015-10-14 02:19:46 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto new_format = has_format() ? modifiable_format() : workbook().create_format();
|
2018-04-25 05:58:17 +08:00
|
|
|
format(new_format.number_format(number_format_, optional<bool>(true)));
|
2016-03-14 11:46:01 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::protection(const class protection &protection_)
|
2016-03-14 11:46:01 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto new_format = has_format() ? modifiable_format() : workbook().create_format();
|
2018-04-25 05:58:17 +08:00
|
|
|
format(new_format.protection(protection_, optional<bool>(true)));
|
2016-03-14 11:46:01 +08:00
|
|
|
}
|
|
|
|
|
2015-11-01 22:43:01 +08:00
|
|
|
template <>
|
2016-12-02 21:37:50 +08:00
|
|
|
XLNT_API std::string cell::value() const
|
2015-10-14 02:19:46 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
return value<rich_text>().plain_text();
|
2015-10-14 02:19:46 +08:00
|
|
|
}
|
|
|
|
|
2016-05-15 03:19:08 +08:00
|
|
|
template <>
|
2016-12-23 19:51:30 +08:00
|
|
|
XLNT_API rich_text cell::value() const
|
2016-05-15 03:19:08 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
if (data_type() == cell::type::shared_string)
|
|
|
|
{
|
2018-07-23 11:51:33 +08:00
|
|
|
return workbook().shared_strings(static_cast<std::size_t>(d_->value_numeric_));
|
2017-05-10 20:44:25 +08:00
|
|
|
}
|
|
|
|
|
2016-05-15 03:19:08 +08:00
|
|
|
return d_->value_text_;
|
|
|
|
}
|
|
|
|
|
2015-10-14 02:19:46 +08:00
|
|
|
bool cell::has_value() const
|
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
return d_->type_ != cell::type::empty;
|
2015-10-14 02:19:46 +08:00
|
|
|
}
|
|
|
|
|
2015-11-11 07:58:54 +08:00
|
|
|
std::string cell::to_string() const
|
2015-10-14 02:19:46 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
auto nf = computed_number_format();
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
switch (data_type())
|
2015-10-14 01:56:07 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
case cell::type::empty:
|
2015-11-01 22:43:01 +08:00
|
|
|
return "";
|
2017-07-09 01:19:55 +08:00
|
|
|
case cell::type::date:
|
2017-05-10 20:44:25 +08:00
|
|
|
case cell::type::number:
|
2017-09-09 09:05:34 +08:00
|
|
|
return nf.format(value<double>(), base_date());
|
2017-05-10 20:44:25 +08:00
|
|
|
case cell::type::inline_string:
|
|
|
|
case cell::type::shared_string:
|
|
|
|
case cell::type::formula_string:
|
2015-11-01 22:43:01 +08:00
|
|
|
case cell::type::error:
|
2016-12-02 21:37:50 +08:00
|
|
|
return nf.format(value<std::string>());
|
2015-11-01 22:43:01 +08:00
|
|
|
case cell::type::boolean:
|
2017-09-09 09:05:34 +08:00
|
|
|
return value<double>() == 0.0 ? "FALSE" : "TRUE";
|
2015-10-14 01:56:07 +08:00
|
|
|
}
|
2016-12-11 02:39:51 +08:00
|
|
|
|
|
|
|
return "";
|
2015-10-14 02:19:46 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2016-05-15 01:57:07 +08:00
|
|
|
bool cell::has_format() const
|
2015-10-24 02:42:36 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return d_->format_.is_set();
|
2015-10-24 02:42:36 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
void cell::format(const class format new_format)
|
2015-10-24 02:42:36 +08:00
|
|
|
{
|
2016-11-10 08:52:18 +08:00
|
|
|
if (has_format())
|
|
|
|
{
|
|
|
|
format().d_->references -= format().d_->references > 0 ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
++new_format.d_->references;
|
2016-11-20 05:50:35 +08:00
|
|
|
d_->format_ = new_format.d_;
|
2016-08-05 13:52:05 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
calendar cell::base_date() const
|
2015-10-19 03:30:46 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
return workbook().base_date();
|
2015-10-19 03:30:46 +08:00
|
|
|
}
|
2015-11-01 22:43:01 +08:00
|
|
|
|
2018-07-02 06:29:58 +08:00
|
|
|
bool operator==(std::nullptr_t, const cell &cell)
|
|
|
|
{
|
|
|
|
return cell.data_type() == cell::type::empty;
|
|
|
|
}
|
|
|
|
|
2018-07-10 13:19:56 +08:00
|
|
|
bool operator==(const cell &cell, std::nullptr_t)
|
|
|
|
{
|
|
|
|
return nullptr == cell;
|
|
|
|
}
|
|
|
|
|
2016-11-21 00:06:52 +08:00
|
|
|
XLNT_API std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
|
2015-11-20 11:54:54 +08:00
|
|
|
{
|
|
|
|
return stream << cell.to_string();
|
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
void cell::value(const std::string &value_string, bool infer_type)
|
2016-05-12 07:24:53 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
value(value_string);
|
|
|
|
|
2017-05-10 20:44:25 +08:00
|
|
|
if (!infer_type || value_string.empty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value_string.front() == '=' && value_string.size() > 1)
|
|
|
|
{
|
|
|
|
formula(value_string);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value_string.front() == '#' && value_string.size() > 1)
|
2016-12-02 21:37:50 +08:00
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
error(value_string);
|
2016-12-02 21:37:50 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto percentage = cast_percentage(value_string);
|
2016-11-20 05:50:35 +08:00
|
|
|
|
|
|
|
if (percentage.first)
|
|
|
|
{
|
|
|
|
d_->value_numeric_ = percentage.second;
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = cell::type::number;
|
2016-12-02 21:37:50 +08:00
|
|
|
number_format(xlnt::number_format::percentage());
|
2016-11-20 05:50:35 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto time = cast_time(value_string);
|
2016-11-20 05:50:35 +08:00
|
|
|
|
|
|
|
if (time.first)
|
|
|
|
{
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = cell::type::number;
|
2016-12-02 21:37:50 +08:00
|
|
|
number_format(number_format::date_time6());
|
2016-11-20 05:50:35 +08:00
|
|
|
d_->value_numeric_ = time.second.to_number();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto numeric = cast_numeric(value_string);
|
2016-11-20 05:50:35 +08:00
|
|
|
|
|
|
|
if (numeric.first)
|
|
|
|
{
|
|
|
|
d_->value_numeric_ = numeric.second;
|
2017-05-10 20:44:25 +08:00
|
|
|
d_->type_ = cell::type::number;
|
2016-11-20 05:50:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-12 07:24:53 +08:00
|
|
|
}
|
|
|
|
|
2016-06-11 01:40:50 +08:00
|
|
|
void cell::clear_format()
|
|
|
|
{
|
2018-07-02 17:06:12 +08:00
|
|
|
if (d_->format_.is_set())
|
|
|
|
{
|
|
|
|
format().d_->references -= format().d_->references > 0 ? 1 : 0;
|
|
|
|
d_->format_.clear();
|
|
|
|
}
|
2016-06-11 01:40:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void cell::clear_style()
|
|
|
|
{
|
2016-11-01 20:50:29 +08:00
|
|
|
if (has_format())
|
|
|
|
{
|
2016-11-08 10:11:30 +08:00
|
|
|
modifiable_format().clear_style();
|
2016-11-01 20:50:29 +08:00
|
|
|
}
|
2016-06-11 01:40:50 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
void cell::style(const class style &new_style)
|
2016-06-11 01:40:50 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
auto new_format = has_format() ? format() : workbook().create_format();
|
2019-03-06 17:45:08 +08:00
|
|
|
|
|
|
|
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());
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
format(new_format.style(new_style));
|
2016-06-11 01:40:50 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
void cell::style(const std::string &style_name)
|
2016-06-11 01:40:50 +08:00
|
|
|
{
|
2016-12-02 21:37:50 +08:00
|
|
|
style(workbook().style(style_name));
|
2016-06-11 01:40:50 +08:00
|
|
|
}
|
|
|
|
|
2017-03-26 22:30:26 +08:00
|
|
|
style cell::style()
|
2016-06-20 02:43:41 +08:00
|
|
|
{
|
2016-11-08 10:11:30 +08:00
|
|
|
if (!has_format() || !format().has_style())
|
2016-06-20 02:43:41 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
throw invalid_attribute();
|
2016-06-20 02:43:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-23 11:51:33 +08:00
|
|
|
auto f = format();
|
2017-03-26 22:30:26 +08:00
|
|
|
|
|
|
|
return f.style();
|
|
|
|
}
|
|
|
|
|
|
|
|
const style cell::style() const
|
|
|
|
{
|
2018-07-23 11:51:33 +08:00
|
|
|
if (!has_format() || !format().has_style())
|
|
|
|
{
|
|
|
|
throw invalid_attribute();
|
|
|
|
}
|
2017-03-26 22:30:26 +08:00
|
|
|
|
2018-07-23 11:51:33 +08:00
|
|
|
return format().style();
|
2016-06-20 02:43:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::has_style() const
|
|
|
|
{
|
2016-11-08 10:11:30 +08:00
|
|
|
return has_format() && format().has_style();
|
2016-11-03 10:04:51 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
format cell::modifiable_format()
|
2016-11-03 10:04:51 +08:00
|
|
|
{
|
2017-01-27 08:57:19 +08:00
|
|
|
if (!d_->format_.is_set())
|
2016-11-20 05:50:35 +08:00
|
|
|
{
|
|
|
|
throw invalid_attribute();
|
|
|
|
}
|
2016-08-18 19:34:18 +08:00
|
|
|
|
2016-12-30 08:00:27 +08:00
|
|
|
return xlnt::format(d_->format_.get());
|
2016-11-03 10:04:51 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 10:11:30 +08:00
|
|
|
const format cell::format() const
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2017-01-27 08:57:19 +08:00
|
|
|
if (!d_->format_.is_set())
|
2016-11-20 05:50:35 +08:00
|
|
|
{
|
|
|
|
throw invalid_attribute();
|
|
|
|
}
|
2016-08-18 19:34:18 +08:00
|
|
|
|
2016-12-30 08:00:27 +08:00
|
|
|
return xlnt::format(d_->format_.get());
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
alignment cell::alignment() const
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return format().alignment();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
border cell::border() const
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return format().border();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
fill cell::fill() const
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return format().fill();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
font cell::font() const
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return format().font();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
number_format cell::number_format() const
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return format().number_format();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
protection cell::protection() const
|
2016-08-18 19:34:18 +08:00
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
return format().protection();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cell::has_hyperlink() const
|
|
|
|
{
|
2016-12-26 22:38:26 +08:00
|
|
|
return d_->hyperlink_.is_set();
|
2016-08-18 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2016-10-29 22:23:04 +08:00
|
|
|
// comment
|
|
|
|
|
|
|
|
bool cell::has_comment()
|
|
|
|
{
|
2016-11-08 10:11:30 +08:00
|
|
|
return d_->comment_.is_set();
|
2016-10-29 22:23:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void cell::clear_comment()
|
|
|
|
{
|
2017-09-09 07:41:34 +08:00
|
|
|
if (has_comment())
|
|
|
|
{
|
|
|
|
d_->parent_->comments_.erase(reference().to_string());
|
|
|
|
d_->comment_.clear();
|
|
|
|
}
|
2016-10-29 22:23:04 +08:00
|
|
|
}
|
|
|
|
|
2016-10-29 22:36:46 +08:00
|
|
|
class comment cell::comment()
|
2016-10-29 22:23:04 +08:00
|
|
|
{
|
|
|
|
if (!has_comment())
|
|
|
|
{
|
2016-11-20 05:50:35 +08:00
|
|
|
throw xlnt::exception("cell has no comment");
|
2016-10-29 22:23:04 +08:00
|
|
|
}
|
|
|
|
|
2017-09-09 07:41:34 +08:00
|
|
|
return *d_->comment_.get();
|
2016-10-29 22:23:04 +08:00
|
|
|
}
|
|
|
|
|
2016-11-13 06:38:29 +08:00
|
|
|
void cell::comment(const std::string &text, const std::string &author)
|
|
|
|
{
|
2018-07-28 10:04:22 +08:00
|
|
|
comment(xlnt::comment(text, author));
|
2016-11-13 06:38:29 +08:00
|
|
|
}
|
|
|
|
|
2016-12-23 19:51:30 +08:00
|
|
|
void cell::comment(const std::string &text, const class font &comment_font, const std::string &author)
|
|
|
|
{
|
2018-07-28 10:04:22 +08:00
|
|
|
comment(xlnt::comment(xlnt::rich_text(text, comment_font), author));
|
2016-12-23 19:51:30 +08:00
|
|
|
}
|
|
|
|
|
2016-10-29 22:23:04 +08:00
|
|
|
void cell::comment(const class comment &new_comment)
|
|
|
|
{
|
2017-09-09 07:41:34 +08:00
|
|
|
if (has_comment())
|
|
|
|
{
|
|
|
|
*d_->comment_.get() = new_comment;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d_->parent_->comments_[reference().to_string()] = new_comment;
|
|
|
|
d_->comment_.set(&d_->parent_->comments_[reference().to_string()]);
|
|
|
|
}
|
2016-11-13 06:38:29 +08:00
|
|
|
|
|
|
|
// offset comment 5 pixels down and 5 pixels right of the top right corner of the cell
|
2016-12-02 21:37:50 +08:00
|
|
|
auto cell_position = anchor();
|
2016-12-26 22:38:26 +08:00
|
|
|
cell_position.first += static_cast<int>(width()) + 5;
|
2016-11-13 06:38:29 +08:00
|
|
|
cell_position.second += 5;
|
2016-11-20 05:50:35 +08:00
|
|
|
|
2017-09-09 07:41:34 +08:00
|
|
|
d_->comment_.get()->position(cell_position.first, cell_position.second);
|
2016-11-13 06:38:29 +08:00
|
|
|
|
2016-12-02 21:37:50 +08:00
|
|
|
worksheet().register_comments_in_manifest();
|
2016-10-29 22:23:04 +08:00
|
|
|
}
|
|
|
|
|
2016-12-24 23:04:57 +08:00
|
|
|
double cell::width() const
|
|
|
|
{
|
|
|
|
return worksheet().column_width(column());
|
|
|
|
}
|
|
|
|
|
|
|
|
double cell::height() const
|
|
|
|
{
|
|
|
|
return worksheet().row_height(row());
|
|
|
|
}
|
|
|
|
|
2014-05-31 06:42:25 +08:00
|
|
|
} // namespace xlnt
|